// AcDbExt.cpp: implementation of the AcDbExt class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "AcDbExt.h"
#include "EdVector3d.h"

#include <math.h>

namespace AcDbExt
{
void TransformOnUnparallel( const AcGeVector3d& vx, const AcGeVector3d& vy, const AcGeVector3d& vz
			, const AcGeVector3d& kXAxis, const AcGeVector3d& kYAxis, const AcGeVector3d& kZAxis, AcDbEntity* ent )
{
	AcGeVector3d vRef;
	double dAngle = 0.0f;

	AcGeMatrix3d map;
	vRef = kZAxis.crossProduct( vz );
	dAngle = kZAxis.angleTo( vz, vRef );
	map.setToRotation( dAngle, vRef, AcGePoint3d::kOrigin );
	ent->transformBy( map );
	
	AcGeVector3d y( kYAxis );
	y.rotateBy( dAngle, vRef );
	if ( !y.isParallelTo( vy ) )
	{
		vRef = y.crossProduct( vy );
		dAngle = y.angleTo( vy );
		map.setToRotation( dAngle, vRef, AcGePoint3d::kOrigin );
		ent->transformBy( map );
		return;
	}
	
	AcGeVector3d x( kXAxis );
	x.rotateBy( dAngle, vRef );
	if ( !x.isParallelTo( vx ) )
	{
		vRef = x.crossProduct( vx );
		dAngle = x.angleTo( vx );
		map.setToRotation( dAngle, vRef, AcGePoint3d::kOrigin );
		ent->transformBy( map );
		return;
	}

	if ( !y.isCodirectionalTo( vy ) )
	{
		dAngle = y.angleTo( vy );
		map.setToRotation( dAngle, vz, AcGePoint3d::kOrigin );
		ent->transformBy( map );
		return;
	}
}

void TransformDbEntityToAnotherCS( AcDbEntity* ent, const AcGeMatrix3d& srcCS, const AcGeMatrix3d& destCS )
{
	AcGePoint3d pt( srcCS( 0, 3 ), srcCS( 1, 3 ), srcCS( 2, 3 ) );
	AcGeVector3d vz( srcCS( 0, 2 ), srcCS( 1, 2 ), srcCS( 2, 2 ) );
	AcGeVector3d vx( srcCS( 0, 0 ), srcCS( 1, 0 ), srcCS( 2, 0 ) );
	AcGeVector3d vy( srcCS( 0, 1 ), srcCS( 1, 1 ), srcCS( 2, 1 ) );
	AcGePoint3d kOrigin( destCS( 0, 3 ), destCS( 1, 3 ), destCS( 2, 3 ) );
	AcGeVector3d kZAxis( destCS( 0, 2 ), destCS( 1, 2 ), destCS( 2, 2 ) );
	AcGeVector3d kXAxis( destCS( 0, 0 ), destCS( 1, 0 ), destCS( 2, 0 ) );
	AcGeVector3d kYAxis( destCS( 0, 1 ), destCS( 1, 1 ), destCS( 2, 1 ) );

	AcGeMatrix3d map;
	AcGeVector3d vRef;
	double dAngle = 0.0f;
	if ( !kZAxis.isParallelTo( vz ) )
	{
		TransformOnUnparallel( vx, vy, vz, kXAxis, kYAxis, kZAxis, ent );
	}
	else if ( !kYAxis.isParallelTo( vy ) )
	{
		TransformOnUnparallel( vz, vx, vy, kZAxis, kXAxis, kYAxis, ent );
	}
	else if ( kZAxis.isCodirectionalTo( vz ) )
	{
		dAngle = kYAxis.angleTo( vy, vz );
		map.setToRotation( dAngle, vz, kOrigin );
		ent->transformBy( map );
	}
	else if ( kYAxis.isCodirectionalTo( vy ) )
	{
		dAngle = kZAxis.angleTo( vz, vy );
		map.setToRotation( dAngle, vy, kOrigin );
		ent->transformBy( map );
	}
	else if ( kXAxis.isCodirectionalTo( vx ) )
	{
		dAngle = kZAxis.angleTo( vz, vx );
		map.setToRotation( dAngle, vx, kOrigin );
		ent->transformBy( map );
	}
	map.setToTranslation( pt - kOrigin );
	ent->transformBy( map );
}

void TransformDbEntityToWCS( AcDbEntity* ent, const AcGeMatrix3d& srcCS )
{
	AcGePoint3d pt( srcCS( 0, 3 ), srcCS( 1, 3 ), srcCS( 2, 3 ) );
	AcGeVector3d vz( srcCS( 0, 2 ), srcCS( 1, 2 ), srcCS( 2, 2 ) );
	AcGeVector3d vx( srcCS( 0, 0 ), srcCS( 1, 0 ), srcCS( 2, 0 ) );
	AcGeVector3d vy( srcCS( 0, 1 ), srcCS( 1, 1 ), srcCS( 2, 1 ) );

	AcGeMatrix3d map;
	AcGeVector3d vRef;
	double dAngle = 0.0f;
	if ( !AcGeVector3d::kZAxis.isParallelTo( vz ) )
	{
		TransformOnUnparallel( vx, vy, vz, AcGeVector3d::kXAxis, AcGeVector3d::kYAxis, AcGeVector3d::kZAxis, ent );
	}
	else if ( !AcGeVector3d::kYAxis.isParallelTo( vy ) )
	{
		TransformOnUnparallel( vz, vx, vy, AcGeVector3d::kZAxis, AcGeVector3d::kXAxis, AcGeVector3d::kYAxis, ent );
	}
	else if ( AcGeVector3d::kZAxis.isCodirectionalTo( vz ) )
	{
		dAngle = AcGeVector3d::kYAxis.angleTo( vy, vz );
		map.setToRotation( dAngle, vz, AcGePoint3d::kOrigin );
		ent->transformBy( map );
	}
	else if ( AcGeVector3d::kYAxis.isCodirectionalTo( vy ) )
	{
		dAngle = AcGeVector3d::kZAxis.angleTo( vz, vy );
		map.setToRotation( dAngle, vy, AcGePoint3d::kOrigin );
		ent->transformBy( map );
	}
	else if ( AcGeVector3d::kXAxis.isCodirectionalTo( vx ) )
	{
		dAngle = AcGeVector3d::kZAxis.angleTo( vz, vx );
		map.setToRotation( dAngle, vx, AcGePoint3d::kOrigin );
		ent->transformBy( map );
	}
	map.setToTranslation( pt - AcGePoint3d::kOrigin );
	ent->transformBy( map );
}
}
